package com.amu.aidemo.android.xfyun

import android.util.Base64
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.*
import org.json.JSONObject
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat
import java.util.*
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

private const val TAG = "XfyunTtsClient"

/**
 * 讯飞语音合成（TTS）客户端
 * API 文档: https://www.xfyun.cn/doc/tts/online_tts/API.html
 */
class XfyunTtsClient(
    private val appId: String,
    private val apiKey: String,
    private val apiSecret: String
) {
    companion object {
        private const val HOST_URL = "wss://tts-api.xfyun.cn/v2/tts"
        private const val CONNECT_TIMEOUT = 30L
        private const val READ_TIMEOUT = 60L
        private const val WRITE_TIMEOUT = 60L
    }

    private var webSocket: WebSocket? = null
    private var okHttpClient: OkHttpClient? = null
    @Volatile
    var isConnected = false
        private set
    private val audioDataBuffer = mutableListOf<ByteArray>()

    // 回调
    var onAudioData: ((ByteArray) -> Unit)? = null
    var onComplete: (() -> Unit)? = null
    var onError: ((String) -> Unit)? = null
    var onConnected: (() -> Unit)? = null

    /**
     * 连接到讯飞服务器
     */
    suspend fun connect() = withContext(Dispatchers.IO) {
        try {
            val authUrl = getAuthUrl()
            Log.d(TAG, "Connecting to TTS service: $authUrl")

            val request = Request.Builder()
                .url(authUrl)
                .build()

            okHttpClient = OkHttpClient.Builder()
                .connectTimeout(CONNECT_TIMEOUT, java.util.concurrent.TimeUnit.SECONDS)
                .readTimeout(READ_TIMEOUT, java.util.concurrent.TimeUnit.SECONDS)
                .writeTimeout(WRITE_TIMEOUT, java.util.concurrent.TimeUnit.SECONDS)
                .pingInterval(20, java.util.concurrent.TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build()

            webSocket = okHttpClient?.newWebSocket(request, object : WebSocketListener() {
                override fun onOpen(webSocket: WebSocket, response: Response) {
                    Log.i(TAG, "TTS WebSocket connected")
                    isConnected = true
                    audioDataBuffer.clear()
                    onConnected?.invoke()
                }

                override fun onMessage(webSocket: WebSocket, text: String) {
                    handleMessage(text)
                }

                override fun onFailure(
                    webSocket: WebSocket,
                    t: Throwable,
                    response: Response?
                ) {
                    Log.e(TAG, "TTS WebSocket error", t)
                    isConnected = false
                    
                    val errorMsg = when {
                        t is java.net.SocketException -> "网络连接断开，请检查网络"
                        t is java.net.SocketTimeoutException -> "连接超时，请重试"
                        t is javax.net.ssl.SSLException -> "SSL 连接失败"
                        response?.code == 401 -> "认证失败，${response.message}"
                        response?.code == 403 -> "无权限访问，请检查服务是否开通"
                        else -> "连接失败: ${t.message}"
                    }
                    
                    onError?.invoke(errorMsg)
                }

                override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                    Log.d(TAG, "TTS WebSocket closed: $code - $reason")
                    isConnected = false
                }
            })
        } catch (e: Exception) {
            Log.e(TAG, "Failed to connect", e)
            onError?.invoke("连接异常: ${e.message}")
        }
    }

    /**
     * 发送文本进行语音合成
     * @param text 要合成的文本（最大 8000 字节）
     * @param voiceName 发音人，默认 xiaoyan（小燕）
     * @param speed 语速，范围 0-100，默认 50
     * @param pitch 音调，范围 0-100，默认 50
     * @param volume 音量，范围 0-100，默认 50
     */
    fun synthesize(
        text: String,
        voiceName: String = "xiaoyan",
        speed: Int = 50,
        pitch: Int = 50,
        volume: Int = 50
    ) {
        if (!isConnected) {
            Log.w(TAG, "Not connected, cannot synthesize")
            onError?.invoke("未连接到服务器")
            return
        }

        try {
            // 将文本转为 Base64
            val textBase64 = Base64.encodeToString(
                text.toByteArray(StandardCharsets.UTF_8),
                Base64.NO_WRAP
            )

            val json = JSONObject().apply {
                put("common", JSONObject().apply {
                    put("app_id", appId)
                })
                Log.d(TAG, "appKey: $apiKey")
                put("business", JSONObject().apply {
                    put("aue", "raw") // 音频编码：raw（PCM）、lame（MP3）
                    put("auf", "audio/L16;rate=16000") // 音频采样率
                    put("vcn", voiceName) // 发音人
                    put("speed", speed) // 语速
                    put("pitch", pitch) // 音调
                    put("volume", volume) // 音量
                    put("tte", "UTF8") // 文本编码格式
                })

                put("data", JSONObject().apply {
                    put("status", 2) // 2 表示数据发送结束
                    put("text", textBase64)
                })
            }

            val message = json.toString()
            webSocket?.send(message)
            Log.d(TAG, "Sent synthesis request: text='$text', voice=$voiceName")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to send synthesis request", e)
            onError?.invoke("发送合成请求失败: ${e.message}")
        }
    }

    /**
     * 处理服务器返回的消息
     */
    private fun handleMessage(message: String) {
        try {
            val json = JSONObject(message)
            val code = json.getInt("code")
            val sid = json.optString("sid", "")

            if (code != 0) {
                val errorMessage = json.optString("message", "Unknown error")
                Log.e(TAG, "TTS error: code=$code, message=$errorMessage, sid=$sid")
                onError?.invoke("合成错误: $errorMessage (code: $code)")
                return
            }

            // 解析音频数据
            if (json.has("data")) {
                val data = json.getJSONObject("data")
                val status = data.getInt("status")
                
                // 获取音频数据
                if (data.has("audio")) {
                    val audioBase64 = data.getString("audio")
                    if (audioBase64.isNotEmpty()) {
                        val audioData = Base64.decode(audioBase64, Base64.NO_WRAP)
                        audioDataBuffer.add(audioData)
                        onAudioData?.invoke(audioData)
                        Log.v(TAG, "Received audio chunk: ${audioData.size} bytes")
                    }
                }

                // status=2 表示合成结束
                if (status == 2) {
                    Log.i(TAG, "TTS synthesis completed, total chunks: ${audioDataBuffer.size}")
                    onComplete?.invoke()
                    disconnect()
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Failed to parse TTS message", e)
            onError?.invoke("解析响应失败: ${e.message}")
        }
    }

    /**
     * 获取所有音频数据（合并后）
     */
    fun getAllAudioData(): ByteArray {
        val totalSize = audioDataBuffer.sumOf { it.size }
        val result = ByteArray(totalSize)
        var offset = 0
        
        audioDataBuffer.forEach { chunk ->
            System.arraycopy(chunk, 0, result, offset, chunk.size)
            offset += chunk.size
        }
        
        return result
    }

    /**
     * 生成鉴权 URL
     */
    private fun getAuthUrl(): String {
        val date = getGMTDate()
        val host = "tts-api.xfyun.cn"
        val requestLine = "GET /v2/tts HTTP/1.1"

        // 1. 生成 signature_origin
        val signatureOrigin = "host: $host\ndate: $date\n$requestLine"

        // 2. 使用 HMAC-SHA256 加密
        val mac = Mac.getInstance("HmacSHA256")
        val secretKeySpec = SecretKeySpec(apiSecret.toByteArray(StandardCharsets.UTF_8), "HmacSHA256")
        mac.init(secretKeySpec)
        val signatureSha = mac.doFinal(signatureOrigin.toByteArray(StandardCharsets.UTF_8))

        // 3. Base64 编码
        val signature = Base64.encodeToString(signatureSha, Base64.NO_WRAP)

        // 4. 生成 authorization_origin
        val authorizationOrigin = "api_key=\"$apiKey\", algorithm=\"hmac-sha256\", " +
                "headers=\"host date request-line\", signature=\"$signature\""

        // 5. Base64 编码 authorization
        val authorization = Base64.encodeToString(
            authorizationOrigin.toByteArray(StandardCharsets.UTF_8),
            Base64.NO_WRAP
        )

        // 6. 拼接最终 URL
        return "$HOST_URL?authorization=$authorization&date=${java.net.URLEncoder.encode(date, "UTF-8")}&host=$host"
    }

    /**
     * 获取 GMT 格式的日期
     */
    private fun getGMTDate(): String {
        val sdf = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US)
        sdf.timeZone = TimeZone.getTimeZone("GMT")
        return sdf.format(Date())
    }

    /**
     * 断开连接
     */
    fun disconnect() {
        try {
            isConnected = false
            webSocket?.close(1000, "Client disconnect")
            webSocket = null
            
            okHttpClient?.dispatcher?.executorService?.shutdown()
            okHttpClient?.connectionPool?.evictAll()
            okHttpClient = null
            
            Log.d(TAG, "TTS Disconnected")
        } catch (e: Exception) {
            Log.e(TAG, "Error during disconnect", e)
        }
    }

    /**
     * 清空音频缓冲区
     */
    fun clearBuffer() {
        audioDataBuffer.clear()
    }
}
